
#include		"PvpW.hh"
#include		"Tools.hpp"

PvpW::PvpW(sf::RenderWindow &app, IGUI::e_context &f, sf::Event &e, Gomoku::Data &i)
  : info(i), focus(f), action(), App(app), Event(e), Input(this->App.GetInput()),
    sizeLeftMenu(200), p1(true), Interpret(i), Wpoint(0), Bpoint(0)
{
  int		wblock, hblock;

  this->action[sf::Event::KeyPressed] = &PvpW::gere_key;
  this->action[sf::Event::MouseButtonPressed] = &PvpW::mouse;
  this->action[sf::Event::Resized] = &PvpW::resized;
  this->proto["REM"] = &PvpW::rem;
  this->proto["ADD"] = &PvpW::add;
  this->proto["YOURTURN"] = &PvpW::yourturn;
  this->proto["RULES"] = &PvpW::rules;
  if (!this->_Platform.LoadFromFile("sprites/goban.png"))
      throw ImgException("LoadFromFile(sprites/goban.png) in PvpW.cpp");
  wblock = ((this->App.GetWidth() - this->sizeLeftMenu) / 19);
  hblock = ((this->App.GetHeight()) / 19);
  if (!this->_bpawn.LoadFromFile("sprites/blackpawn.png"))
      throw ImgException("LoadFromFile(sprites/blackpawn.png) in PvpW.cpp");
  if (!this->_wpawn.LoadFromFile("sprites/whitepawn.png"))
      throw ImgException("LoadFromFile(sprites/whitepawn.png) in PvpW.cpp");
  if (!this->_menu.LoadFromFile("sprites/greenmenu.jpg"))
      throw ImgException("LoadFromFile(sprites/greenmenu.jpg) in PvpW.cpp");
  this->Platform.SetImage(this->_Platform);
  this->menu.SetImage(this->_menu);
  this->Platform.Resize(this->App.GetWidth() - this->sizeLeftMenu, this->App.GetHeight());
  this->menu.Resize(this->sizeLeftMenu, this->App.GetHeight());
  this->Platform.SetPosition(this->sizeLeftMenu, 0);
  this->menu.SetPosition(0, 0);
  this->Score.SetFont(this->info.getGomofont());
  this->focusmouse.push_back(new GObject(this->_wpawn, 2));
  this->focusmouse.push_back(new GObject(this->_bpawn, 2));
  this->focusmouse[0]->resize(wblock, hblock);
  this->focusmouse[1]->resize(wblock, hblock);
}

PvpW::~PvpW(void)
{
}

void		PvpW::run(void)
{
  this->takeCmd();
  this->App.Clear();
  this->App.Draw(this->menu);
  this->App.Draw(this->Platform);
  this->Score.SetSize(this->info.getSizefont() + 10);
  if (this->action.find(this->Event.Type) != this->action.end())
    (this->*(this->action.find(Event.Type)->second))();
  for (std::map<int, GObject*>::iterator it = this->pawn.begin(); it != this->pawn.end(); it++)
    it->second->draw(this->App);
  this->Score.SetStyle(sf::String::Regular);
  if (!this->p1 && this->Wpoint < 10)
    this->Score.SetStyle(sf::String::Underlined);
  this->Score.SetPosition(10.f, 180.f);
  this->Score.SetColor(sf::Color(255, 255, 255));
  this->Score.SetText(std::string("White: ") + std::string(TToString<int>(this->Wpoint)));
  this->App.Draw(this->Score);
  this->Score.SetStyle(sf::String::Regular);
  if (this->p1 && this->Bpoint < 10)
    this->Score.SetStyle(sf::String::Underlined);
  this->Score.SetPosition(10.f, 100.f);
  this->Score.SetColor(sf::Color(0, 0, 0));
  this->Score.SetText(std::string("Black: ") + std::string(TToString<int>(this->Bpoint)));
  this->App.Draw(this->Score);
  this->checkWin();
  this->mouseHover();
}

void		PvpW::checkWin(void)
{
  if (this->Wpoint > 9 ||
      this->Bpoint > 9 ||
      this->Interpret.getWwin() ||
      this->Interpret.getBwin())
    {
      this->Score.SetPosition(this->App.GetWidth() / 2 - 200, this->App.GetHeight() / 2 - 50);
      this->Score.SetColor(sf::Color(255, 0, 0));
      if (this->Bpoint > 9 || this->Interpret.getBwin())
	this->Score.SetText(std::string("BLACK WIN"));
      else
	this->Score.SetText(std::string("WHITE WIN"));
      this->Score.SetSize(this->info.getSizefont() + 60);
      this->Score.SetStyle(sf::String::Underlined);
      this->App.Draw(this->Score);
      this->Score.SetStyle(sf::String::Regular);
    }
}

void		PvpW::restart(void)
{
  this->Interpret.resetPoint();
  for (std::map<int, GObject*>::iterator it = this->pawn.begin(); it != this->pawn.end(); it++)
    this->pawn.erase(it);
  this->p1 = true;
}

void		PvpW::gere_key(void)
{
  switch (this->Event.Key.Code)
    {
    case sf::Key::Escape:
      this->App.ShowMouseCursor(true);
      this->restart();
      this->focus = IGUI::MAINMENU;
      break;
    default:
      break;
    }
}

void		PvpW::mouse(void)
{
  int		x, y, wblock, hblock;

  wblock = ((this->App.GetWidth() - this->sizeLeftMenu) / 19);
  hblock = ((this->App.GetHeight()) / 19);
  x = (this->Input.GetMouseX() - this->sizeLeftMenu) / wblock;
  y = (this->Input.GetMouseY()) / hblock;
  if (x >= 0 && x < 19 && y >= 0 && y < 19 && this->pawn.find(x * 100 + y) == this->pawn.end() &&
      !(this->Wpoint > 9 ||
	this->Bpoint > 9 ||
	this->Interpret.getWwin() ||
	this->Interpret.getBwin()) && !this->p1)
    {
      this->info.getNetwork().ClientPacket << "PLAY " + TToString<int>(x) + " " + TToString<int>(y) + "\n";
      this->info.getNetwork().Client.Send(this->info.getNetwork().ClientPacket);
      this->info.getNetwork().ClientPacket.Clear();
      this->pawn[x * 100 + y] = new GObject(this->_wpawn, 2);
      this->pawn[x * 100 + y]->setId(0);
      this->p1 = true;
      this->pawn[x * 100 + y]->resize(wblock, hblock);
      this->pawn[x * 100 + y]->setPos((x * wblock) + this->sizeLeftMenu + x * 0.4, y * hblock + y * 0.4);
    }
}

void		PvpW::resized(void)
{
  this->App.SetSize(1024, 768);
}

void		PvpW::mouseHover(void)
{
  int		x, y, wblock, hblock;

  wblock = ((this->App.GetWidth() - this->sizeLeftMenu) / 19);
  hblock = ((this->App.GetHeight()) / 19);
  x = (this->Input.GetMouseX() - this->sizeLeftMenu) / wblock;
  y = (this->Input.GetMouseY()) / hblock;
  if (this->Input.GetMouseX() >= this->sizeLeftMenu && x >= 0 && x < 19 && y >= 0 && y < 19)
    {
      this->App.ShowMouseCursor(false);
      this->focusmouse[0]->setPos((x * wblock) + this->sizeLeftMenu + x * 0.4, y * hblock + y * 0.4);
      if (x >= 0 && x < 19 && y >= 0 && y < 19 && this->pawn.find(x * 100 + y) == this->pawn.end() && !this->p1)
	this->focusmouse[0]->setState(0);
      else
	this->focusmouse[0]->setState(1);
      this->focusmouse[0]->draw(this->App);
    }
  else
    this->App.ShowMouseCursor(true);
}

void		PvpW::takeCmd(void)
{
  std::string	strp1, cmd;

  if (this->info.getNetwork().isConnected)
    {
      this->info.getNetwork().Client.SetBlocking(false); 
      this->info.getNetwork().Client.Receive(this->info.getNetwork().ClientPacket);
      while (!this->info.getNetwork().ClientPacket.EndOfPacket())
  	{
  	  this->info.getNetwork().ClientPacket >> strp1;
	  cmd = this->takeWord(strp1, 0);
	  if (this->proto.find(cmd) != this->proto.end())
	    (this->*(this->proto.find(cmd)->second))(strp1);
	  else
	    std::cout << cmd << ": Command not found" << std::endl;
  	}
      this->info.getNetwork().ClientPacket.Clear();
    }
}

std::string	PvpW::takeWord(std::string &str, int nword)
{
  size_t	count = 0, posend = 0;

  while (nword != 0 && count < str.size() - 1)
    {
      if (str.at(count) == ' ')
	nword--;
      count++;
    }
  if (nword != 0)
    return ("");
  while (count + posend < str.size() - 1 && str.at(count + posend) != ' ')
    posend++;
  return (str.substr(count, posend));
}

void		PvpW::rem(std::string &str)
{
  int		x1, y1, x2, y2;

  if (this->p1)
    this->Wpoint += 2;
  else
    this->Bpoint += 2;
  x1 = atoi(this->takeWord(str, 1).c_str());
  y1 = atoi(this->takeWord(str, 2).c_str());
  x2 = atoi(this->takeWord(str, 3).c_str());
  y2 = atoi(this->takeWord(str, 4).c_str());
  this->pawn.erase(x1 * 100 + y1);
  this->pawn.erase(x2 * 100 + y2);
}

void		PvpW::add(std::string &str)
{
  int		x, y, wblock, hblock;

  wblock = ((this->App.GetWidth() - this->sizeLeftMenu) / 19);
  hblock = ((this->App.GetHeight()) / 19);
  x = atoi(this->takeWord(str, 1).c_str());
  y = atoi(this->takeWord(str, 2).c_str());
  
  this->pawn[x * 100 + y] = new GObject(this->_bpawn, 2);
  this->pawn[x * 100 + y]->setId(1);
  this->pawn[x * 100 + y]->resize(wblock, hblock);
  this->pawn[x * 100 + y]->setPos((x * wblock) + this->sizeLeftMenu + x * 0.4, y * hblock + y * 0.4);
}

void		PvpW::yourturn(std::string &str)
{
  std::cout << str << std::endl;
  this->p1 = false;
}

void		PvpW::rules(std::string &str)
{
  this->r3 = atoi(this->takeWord(str, 1).c_str());
  this->r5 = atoi(this->takeWord(str, 2).c_str());
  this->timeout = atoi(this->takeWord(str, 3).c_str());
  std::cout << this->r3 << ":" << this->r5 << ":" << this->timeout << std::endl;
}
